1 <!DOCTYPE html PUBLIC
"-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
4 <meta http-equiv=
"Content-Type" content=
"text/html; charset=UTF-8">
5 <meta http-equiv=
"Content-Style-Type" content=
"text/css">
7 <meta name=
"Generator" content=
"Cocoa HTML Writer">
8 <meta name=
"CocoaVersion" content=
"949.35">
9 <style type=
"text/css">
10 p
.p1
{margin: 0.0px 0.0px 0.0px 0.0px; font: 21.0px Helvetica
}
11 p
.p2
{margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica
; min-height: 18.0px}
12 p
.p3
{margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica
}
13 p
.p4
{margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco
; color: #9b1e10}
14 p
.p5
{margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco
; color: #0025b4}
15 p
.p6
{margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco
; color: #9b1e10; min-height: 16.0px}
16 p
.p7
{margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco
}
17 p
.p8
{margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco
; min-height: 16.0px}
18 p
.p9
{margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Monaco
}
19 p
.p10
{margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Monaco
; min-height: 19.0px}
20 p
.p11
{margin: 0.0px 0.0px 0.0px 0.0px; font: 19.0px Monaco
; min-height: 26.0px}
21 p
.p12
{margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px Helvetica
; min-height: 16.0px}
22 p
.p13
{margin: 0.0px 0.0px 0.0px 0.0px}
23 p
.p14
{margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Times
; min-height: 14.0px}
24 p
.p15
{margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco
; color: #606060}
25 p
.p16
{margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco
; color: #000000}
26 p
.p17
{margin: 0.0px 0.0px 0.0px 0.0px; font: 21.0px Helvetica
; min-height: 25.0px}
27 span
.s1
{color: #000000}
28 span
.s2
{color: #0025b4}
29 span
.s3
{font: 12.0px Monaco
; color: #0025b4}
30 span
.s4
{font: 14.0px Monaco
}
31 span
.s5
{font: 14.0px Courier
}
32 span
.s6
{font: 12.0px Helvetica
}
33 span
.s7
{color: #606060}
34 span
.s8
{color: #416c1c}
35 span
.s9
{font: 12.0px Monaco
}
36 span
.s10
{color: #9b1e10}
37 span
.Apple-tab-span
{white-space:pre
}
41 <p class=
"p1">How Unit Generator plug-ins work.
</p>
42 <p class=
"p2"><br></p>
43 <p class=
"p3">The server loads unit generator plug-ins when it starts up.
</p>
44 <p class=
"p3">Unit Generator plug-ins are dynamically loaded libraries (DLLs) written in C++.
</p>
45 <p class=
"p3">Each library may contain one or multiple unit generator definitions.
</p>
46 <p class=
"p3">The server looks in the
"plugins" directory for all files ending in .scx and calls the load() function in each one.
</p>
47 <p class=
"p2"><br></p>
48 <p class=
"p3"><b>The load() function
</b></p>
49 <p class=
"p2"><br></p>
50 <p class=
"p3">When the library is loaded the server calls the load() function in the library.
</p>
51 <p class=
"p2"><br></p>
52 <p class=
"p3">The load function has two responsibilities:
</p>
53 <p class=
"p3"><span class=
"Apple-tab-span"> </span>• It needs to store the passed in pointer to the InterfaceTable in a global variable.
</p>
54 <p class=
"p3"><span class=
"Apple-tab-span"> </span>• It defines the unit generators.
</p>
55 <p class=
"p2"><span class=
"Apple-tab-span"> </span></p>
56 <p class=
"p4">// InterfaceTable contains pointers to functions in the host (server).
</p>
57 <p class=
"p5"><span class=
"s1">static
</span>InterfaceTable
<span class=
"s1"> *ft;
</span></p>
59 <p class=
"p6"><br></p>
60 <p class=
"p4">// the load function is called by the host when the plug-in is loaded
</p>
61 <p class=
"p7">void load(
<span class=
"s2">InterfaceTable
</span> *inTable)
</p>
63 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span>ft = inTable;
</span>// store pointer to InterfaceTable
</p>
64 <p class=
"p8"><br></p>
65 <p class=
"p5"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>DefineSimpleUnit
<span class=
"s1">(
</span>MySaw
<span class=
"s1">);
</span></p>
67 <p class=
"p2"><br></p>
68 <p class=
"p3">Unit Generators are defined by calling a function in the InterfaceTable and passing it the name of the unit generator, the size of its C data struct, and pointers to functions for constructing and destructing it. The macro
<span class=
"s3">DefineSimpleUnit
</span> makes this more brief.
</p>
69 <p class=
"p2"><br></p>
70 <p class=
"p9">#define DefineSimpleUnit(name) \
</p>
71 <p class=
"p9"><span class=
"Apple-converted-space"> </span>(*ft-
>fDefineUnit)(#name, sizeof(name), (UnitCtorFunc)
&name##_Ctor,
0);
</p>
72 <p class=
"p2"><br></p>
73 <p class=
"p3"><span class=
"s4">ft-
>fDefineUnit
</span>is a function pointer in the InterfaceTable to the server function that defines a new unit generator.
</p>
74 <p class=
"p2"><br></p>
75 <p class=
"p3"><span class=
"s4">#name
</span>creates a string C from the name. In this case,
"MySaw".
</p>
76 <p class=
"p2"><br></p>
77 <p class=
"p3"><span class=
"s4">sizeof(name)
</span>will be the size of the struct MySaw.
</p>
78 <p class=
"p2"><br></p>
79 <p class=
"p3"><span class=
"s4">name##_Ctor
</span>will macro-expand to
<span class=
"s4">MySaw_Ctor
</span>. There will need to be a function defined with this name.
</p>
80 <p class=
"p2"><br></p>
81 <p class=
"p3"><span class=
"s4">0</span> is the argument for the Dtor, or destructor function, which is not needed for this unit generator.
</p>
82 <p class=
"p10"><br></p>
83 <p class=
"p10"><br></p>
84 <p class=
"p3">So the macro:
<span class=
"Apple-converted-space"> </span></p>
85 <p class=
"p2"><br></p>
86 <p class=
"p9">DefineSimpleUnit(MySaw);
<span class=
"Apple-converted-space"> </span></p>
87 <p class=
"p8"><br></p>
88 <p class=
"p3">expands to this:
</p>
89 <p class=
"p2"><br></p>
90 <p class=
"p9">(*ft-
>fDefineUnit)(
"MySaw", sizeof(MySaw), (UnitCtorFunc)
&MySaw_Ctor,
0);
</p>
91 <p class=
"p10"><br></p>
92 <p class=
"p2"><br></p>
93 <p class=
"p3">A plug-in can also define things other than unit generators such as buffer fill (
<span class=
"s5">"/b_gen")
</span> commands.
</p>
94 <p class=
"p11"><span class=
"Apple-tab-span"> </span></p>
95 <p class=
"p11"><br></p>
96 <p class=
"p1">Adding a Target to Xcode
</p>
97 <p class=
"p12"><br></p>
98 <p class=
"p3">You will need to have the Developer Tools installed to do this.
</p>
99 <p class=
"p3">Each group of plugins shares a target in Xcode, which outputs a single plugin, e.g MyUGens.scx.
</p>
100 <p class=
"p2"><br></p>
101 <p class=
"p3">We will use an existing target as a template for our target. In this tutorial we will use ChaosUGens as a template, although you could use any target.
<span class=
"Apple-converted-space"> </span></p>
102 <p class=
"p3">The frist step is to make a duplicate of ChaosUGens. To do this control-click on the ChaosUGens target and select
"Duplicate".
</p>
103 <p class=
"p2"><br></p>
104 <p class=
"p2"><br></p>
105 <p class=
"p13"><span class=
"s6"><img src=
"attachments/Writing_Unit_Generators/Pasted Graphic 1.png" alt=
"attachments/Writing_Unit_Generators/Pasted Graphic 1.png"></span></p>
106 <p class=
"p2"><br></p>
107 <p class=
"p3">Now we need to change the name of the target and it's output file. Double click on the
"ChaosUGens copy" to open it's inspector.
</p>
108 <p class=
"p2"><br></p>
109 <p class=
"p13"><span class=
"s6"><img src=
"attachments/Writing_Unit_Generators/Pasted Graphic 2.png" alt=
"attachments/Writing_Unit_Generators/Pasted Graphic 2.png"></span></p>
110 <p class=
"p2"><br></p>
111 <p class=
"p3">In the
"Build" tab , search for the
"Product Name" setting and change the value to
"MyUGens".
</p>
112 <p class=
"p2"><br></p>
113 <p class=
"p13"><span class=
"s6"><img src=
"attachments/Writing_Unit_Generators/Pasted Graphic 5.png" alt=
"attachments/Writing_Unit_Generators/Pasted Graphic 5.png"></span></p>
114 <p class=
"p14"><br></p>
115 <p class=
"p3">Now switch to the
"General" tab and change the target name to
"MyUGens".
</p>
116 <p class=
"p2"><br></p>
117 <p class=
"p13"><span class=
"s6"><img src=
"attachments/Writing_Unit_Generators/Pasted Graphic.png" alt=
"attachments/Writing_Unit_Generators/Pasted Graphic.png"></span></p>
118 <p class=
"p14"><br></p>
119 <p class=
"p14"><br></p>
120 <p class=
"p3">Close the ChaosUGens inspector, expand the target's disclosure triangle, and then expand the
"Compile Sources" disclosure triangle.
</p>
121 <p class=
"p2"><br></p>
122 <p class=
"p2"><br></p>
123 <p class=
"p13"><span class=
"s6"><img src=
"attachments/Writing_Unit_Generators/Pasted Graphic 10.png" alt=
"attachments/Writing_Unit_Generators/Pasted Graphic 10.png"></span></p>
124 <p class=
"p14"><br></p>
125 <p class=
"p14"><br></p>
126 <p class=
"p3">Delete the existing
"ChaosUGens.cpp" source file by clicking on it and pressing the delete key. Confirm the deletion in the dialog that is presented.
</p>
127 <p class=
"p2"><br></p>
128 <p class=
"p13"><span class=
"s6"><img src=
"attachments/Writing_Unit_Generators/Pasted Graphic 11.png" alt=
"attachments/Writing_Unit_Generators/Pasted Graphic 11.png"></span></p>
129 <p class=
"p14"><br></p>
130 <p class=
"p2"><br></p>
131 <p class=
"p3">Use the
"File->New File..." menu option to create a new source file.
</p>
132 <p class=
"p2"><br></p>
133 <p class=
"p13"><span class=
"s6"><img src=
"attachments/Writing_Unit_Generators/Pasted Graphic 13.png" alt=
"attachments/Writing_Unit_Generators/Pasted Graphic 13.png"></span></p>
134 <p class=
"p2"><br></p>
135 <p class=
"p2"><br></p>
136 <p class=
"p3">Under the BSD section, select
"C++ File", and click
"Next".
</p>
137 <p class=
"p2"><br></p>
138 <p class=
"p13"><span class=
"s6"><img src=
"attachments/Writing_Unit_Generators/Pasted Graphic 14.png" alt=
"attachments/Writing_Unit_Generators/Pasted Graphic 14.png"></span></p>
139 <p class=
"p14"><br></p>
140 <p class=
"p2"><br></p>
141 <p class=
"p3">Change the filename field to
"MyUGens.cpp", uncheck the
"Also create MyUGens.h" option, and check
"MyUGens" as the only target. When all these options have been set, click
"Finish".
</p>
142 <p class=
"p2"><br></p>
143 <p class=
"p2"><br></p>
144 <p class=
"p13"><span class=
"s6"><img src=
"attachments/Writing_Unit_Generators/Pasted Graphic 15.png" alt=
"attachments/Writing_Unit_Generators/Pasted Graphic 15.png"></span></p>
145 <p class=
"p2"><br></p>
146 <p class=
"p3">Erase the default code, and copy the following into the MyUGens.cpp file:
</p>
147 <p class=
"p3">____________________________________________________________________
</p>
148 <p class=
"p8"><br></p>
149 <p class=
"p15"><span class=
"s1">#include
</span>"SC_PlugIn.h"</p>
150 <p class=
"p8"><br></p>
151 <p class=
"p4">// InterfaceTable contains pointers to functions in the host (server).
</p>
152 <p class=
"p5"><span class=
"s1">static
</span>InterfaceTable
<span class=
"s1"> *ft;
</span></p>
153 <p class=
"p8"><br></p>
154 <p class=
"p4">// declare struct to hold unit generator state
</p>
155 <p class=
"p7">struct
<span class=
"s2">MySaw
</span> : public
<span class=
"s2">Unit
</span></p>
157 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span>double mPhase;
</span>// phase of the oscillator, from -
1 to
1.
</p>
158 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span>float mFreqMul;
</span>// a constant for multiplying frequency
</p>
160 <p class=
"p8"><br></p>
161 <p class=
"p4">// declare unit generator functions
<span class=
"Apple-converted-space"> </span></p>
162 <p class=
"p7">extern
<span class=
"s7">"C"</span></p>
164 <p class=
"p7"><span class=
"Apple-tab-span"> </span>void load(
<span class=
"s2">InterfaceTable
</span> *inTable);
</p>
165 <p class=
"p7"><span class=
"Apple-tab-span"> </span>void
<span class=
"s2">MySaw_next_a
</span>(
<span class=
"s2">MySaw
</span> *unit, int inNumSamples);
</p>
166 <p class=
"p7"><span class=
"Apple-tab-span"> </span>void
<span class=
"s2">MySaw_next_k
</span>(
<span class=
"s2">MySaw
</span> *unit, int inNumSamples);
</p>
167 <p class=
"p7"><span class=
"Apple-tab-span"> </span>void
<span class=
"s2">MySaw_Ctor
</span>(
<span class=
"s2">MySaw
</span>* unit);
</p>
169 <p class=
"p8"><br></p>
170 <p class=
"p4">//////////////////////////////////////////////////////////////////
</p>
171 <p class=
"p8"><br></p>
172 <p class=
"p4">// Ctor is called to initialize the unit generator.
<span class=
"Apple-converted-space"> </span></p>
173 <p class=
"p4">// It only executes once.
</p>
174 <p class=
"p8"><br></p>
175 <p class=
"p4">// A Ctor usually does
3 things.
</p>
176 <p class=
"p4">//
1. set the calculation function.
</p>
177 <p class=
"p4">//
2. initialize the unit generator state variables.
</p>
178 <p class=
"p4">//
3. calculate one sample of output.
</p>
179 <p class=
"p5"><span class=
"s1">void
</span>MySaw_Ctor
<span class=
"s1">(
</span>MySaw
<span class=
"s1">* unit)
</span></p>
181 <p class=
"p8"><br></p>
182 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>//
1. set the calculation function.
</p>
183 <p class=
"p7"><span class=
"Apple-tab-span"> </span>if (
<span class=
"s2">INRATE
</span>(
0) == calc_FullRate) {
</p>
184 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// if the frequency argument is audio rate
<span class=
"Apple-converted-space"> </span></p>
185 <p class=
"p5"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>SETCALC
<span class=
"s1">(
</span>MySaw_next_a
<span class=
"s1">);
</span></p>
186 <p class=
"p7"><span class=
"Apple-tab-span"> </span>} else {
</p>
187 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// if the frequency argument is control rate (or a scalar).
</p>
188 <p class=
"p5"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>SETCALC
<span class=
"s1">(
</span>MySaw_next_k
<span class=
"s1">);
</span></p>
189 <p class=
"p7"><span class=
"Apple-tab-span"> </span>}
</p>
190 <p class=
"p8"><br></p>
191 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>//
2. initialize the unit generator state variables.
</p>
192 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// initialize a constant for multiplying the frequency
</p>
193 <p class=
"p7"><span class=
"Apple-tab-span"> </span>unit-
>mFreqMul =
2.0 *
<span class=
"s2">SAMPLEDUR
</span>;
</p>
194 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// get initial phase of oscillator
</p>
195 <p class=
"p7"><span class=
"Apple-tab-span"> </span>unit-
>mPhase =
<span class=
"s2">IN0
</span>(
1);
</p>
196 <p class=
"p8"><span class=
"Apple-tab-span"> </span></p>
197 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>//
3. calculate one sample of output.
</p>
198 <p class=
"p5"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>MySaw_next_k
<span class=
"s1">(unit,
1);
</span></p>
200 <p class=
"p8"><br></p>
201 <p class=
"p8"><br></p>
202 <p class=
"p4">//////////////////////////////////////////////////////////////////
</p>
203 <p class=
"p8"><br></p>
204 <p class=
"p4">// The calculation function executes once per control period
<span class=
"Apple-converted-space"> </span></p>
205 <p class=
"p4">// which is typically
64 samples.
</p>
206 <p class=
"p8"><br></p>
207 <p class=
"p4">// calculation function for an audio rate frequency argument
</p>
208 <p class=
"p7">void
<span class=
"s2">MySaw_next_a
</span>(
<span class=
"s2">MySaw
</span> *unit, int inNumSamples)
</p>
210 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// get the pointer to the output buffer
</p>
211 <p class=
"p7"><span class=
"Apple-tab-span"> </span>float *out =
<span class=
"s2">OUT
</span>(
0);
</p>
212 <p class=
"p8"><span class=
"Apple-tab-span"> </span></p>
213 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// get the pointer to the input buffer
</p>
214 <p class=
"p7"><span class=
"Apple-tab-span"> </span>float *freq =
<span class=
"s2">IN
</span>(
0);
</p>
215 <p class=
"p8"><span class=
"Apple-tab-span"> </span></p>
216 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// get phase and freqmul constant from struct and store it in a
<span class=
"Apple-converted-space"> </span></p>
217 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// local variable.
</p>
218 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// The optimizer will cause them to be loaded it into a register.
</p>
219 <p class=
"p7"><span class=
"Apple-tab-span"> </span>float freqmul = unit-
>mFreqMul;
</p>
220 <p class=
"p7"><span class=
"Apple-tab-span"> </span>double phase = unit-
>mPhase;
</p>
221 <p class=
"p8"><span class=
"Apple-tab-span"> </span></p>
222 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// perform a loop for the number of samples in the control period.
</p>
223 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// If this unit is audio rate then inNumSamples will be
64 or whatever
</p>
224 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// the block size is. If this unit is control rate then inNumSamples will
</p>
225 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// be
1.
</p>
226 <p class=
"p7"><span class=
"Apple-tab-span"> </span>for (int i=
0; i
< inNumSamples; ++i)
</p>
227 <p class=
"p7"><span class=
"Apple-tab-span"> </span>{
</p>
228 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// out must be written last for in place operation
</p>
229 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>float z = phase;
<span class=
"Apple-converted-space"> </span></p>
230 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>phase += freq[i] * freqmul;
</p>
231 <p class=
"p8"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></p>
232 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// these if statements wrap the phase a +
1 or -
1.
</p>
233 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>if (phase
>=
1.f) phase -=
2.f;
</p>
234 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>else if (phase
<= -
1.f) phase +=
2.f;
</p>
235 <p class=
"p8"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></p>
236 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// write the output
</p>
237 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>out[i] = z;
</p>
238 <p class=
"p7"><span class=
"Apple-tab-span"> </span>}
</p>
239 <p class=
"p8"><br></p>
240 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// store the phase back to the struct
</p>
241 <p class=
"p7"><span class=
"Apple-tab-span"> </span>unit-
>mPhase = phase;
</p>
243 <p class=
"p8"><br></p>
244 <p class=
"p4">//////////////////////////////////////////////////////////////////
</p>
245 <p class=
"p8"><br></p>
246 <p class=
"p4">// calculation function for a control rate frequency argument
</p>
247 <p class=
"p7">void
<span class=
"s2">MySaw_next_k
</span>(
<span class=
"s2">MySaw
</span> *unit, int inNumSamples)
</p>
249 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// get the pointer to the output buffer
</p>
250 <p class=
"p7"><span class=
"Apple-tab-span"> </span>float *out =
<span class=
"s2">OUT
</span>(
0);
</p>
251 <p class=
"p8"><br></p>
252 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// freq is control rate, so calculate it once.
</p>
253 <p class=
"p7"><span class=
"Apple-tab-span"> </span>float freq =
<span class=
"s2">IN0
</span>(
0) * unit-
>mFreqMul;
</p>
254 <p class=
"p8"><span class=
"Apple-tab-span"> </span></p>
255 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// get phase from struct and store it in a local variable.
</p>
256 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// The optimizer will cause it to be loaded it into a register.
</p>
257 <p class=
"p7"><span class=
"Apple-tab-span"> </span>double phase = unit-
>mPhase;
</p>
258 <p class=
"p8"><span class=
"Apple-tab-span"> </span></p>
259 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// since the frequency is not changing then we can simplify the loops
<span class=
"Apple-converted-space"> </span></p>
260 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// by separating the cases of positive or negative frequencies.
<span class=
"Apple-converted-space"> </span></p>
261 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// This will make them run faster because there is less code inside the loop.
</p>
262 <p class=
"p7"><span class=
"Apple-tab-span"> </span>if (freq
>=
0.f) {
</p>
263 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// positive frequencies
</p>
264 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>for (int i=
0; i
< inNumSamples; ++i)
</p>
265 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>{
<span class=
"Apple-converted-space"> </span></p>
266 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>out[i] = phase;
</p>
267 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>phase += freq;
</p>
268 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>if (phase
>=
1.f) phase -=
2.f;
</p>
269 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>}
</p>
270 <p class=
"p7"><span class=
"Apple-tab-span"> </span>} else {
</p>
271 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// negative frequencies
</p>
272 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>for (int i=
0; i
< inNumSamples; ++i)
</p>
273 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>{
<span class=
"Apple-converted-space"> </span></p>
274 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>out[i] = phase;
</p>
275 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>phase += freq;
</p>
276 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>if (phase
<= -
1.f) phase +=
2.f;
</p>
277 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>}
</p>
278 <p class=
"p7"><span class=
"Apple-tab-span"> </span>}
</p>
279 <p class=
"p8"><br></p>
280 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// store the phase back to the struct
</p>
281 <p class=
"p7"><span class=
"Apple-tab-span"> </span>unit-
>mPhase = phase;
</p>
283 <p class=
"p8"><br></p>
284 <p class=
"p4">////////////////////////////////////////////////////////////////////
</p>
285 <p class=
"p8"><br></p>
286 <p class=
"p4">// the load function is called by the host when the plug-in is loaded
</p>
287 <p class=
"p7">void load(
<span class=
"s2">InterfaceTable
</span> *inTable)
</p>
289 <p class=
"p7"><span class=
"Apple-tab-span"> </span>ft = inTable;
</p>
290 <p class=
"p8"><br></p>
291 <p class=
"p5"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>DefineSimpleUnit
<span class=
"s1">(
</span>MySaw
<span class=
"s1">);
</span></p>
293 <p class=
"p8"><br></p>
294 <p class=
"p4">////////////////////////////////////////////////////////////////////
</p>
295 <p class=
"p6"><br></p>
296 <p class=
"p3">____________________________________________________________________
</p>
297 <p class=
"p6"><br></p>
298 <p class=
"p3">Drag the MyUGens target into the
"All" aggregate target, and build the project using the
"Build->Build" menu option.
</p>
299 <p class=
"p6"><br></p>
300 <p class=
"p13"><span class=
"s6"><img src=
"attachments/Writing_Unit_Generators/Pasted Graphic 16.png" alt=
"attachments/Writing_Unit_Generators/Pasted Graphic 16.png"></span></p>
301 <p class=
"p14"><br></p>
302 <p class=
"p3">Now launch SuperCollider.app and create a file named MyUGens.sc in the class library. Add the following to this file:
</p>
303 <p class=
"p3">____________________________________________________________________
</p>
304 <p class=
"p8"><br></p>
305 <p class=
"p5">MySaw
<span class=
"s1"> :
</span>UGen
<span class=
"s1"> {
</span></p>
306 <p class=
"p7"><span class=
"Apple-tab-span"> </span>*ar {
<span class=
"s2">arg
</span> freq =
440.0, iphase =
0.0, mul =
1.0, add =
0.0;
</p>
307 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>^
<span class=
"s2">this
</span>.multiNew(
<span class=
"s8">'audio'
</span>, freq, iphase).madd(mul, add)
</p>
308 <p class=
"p7"><span class=
"Apple-tab-span"> </span>}
</p>
309 <p class=
"p7"><span class=
"Apple-tab-span"> </span>*kr {
<span class=
"s2">arg
</span> freq =
440.0, iphase =
0.0, mul =
1.0, add =
0.0;
</p>
310 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>^
<span class=
"s2">this
</span>.multiNew(
<span class=
"s8">'control'
</span>, freq, iphase).madd(mul, add)
</p>
311 <p class=
"p7"><span class=
"Apple-tab-span"> </span>}
</p>
313 <p class=
"p3">____________________________________________________________________
</p>
314 <p class=
"p8"><br></p>
315 <p class=
"p3">The SuperCollider class for your UGen allows the SuperCollider application to be able to write a SynthDef file.
</p>
316 <p class=
"p2"><br></p>
317 <p class=
"p3">The arguments to the MySaw UGen are freq and iphase.
</p>
318 <p class=
"p3">The
<span class=
"s9">multiNew
</span> method handles multi channel expansion.
</p>
319 <p class=
"p3">The
<span class=
"s9">madd
</span> method provides support for the mul and add arguments. It will create a MulAdd UGen if necessary. You could write the class without mul and add arguments, but providing them makes it more convenient for the user.
</p>
320 <p class=
"p2"><br></p>
321 <p class=
"p4">// without mul and add.
</p>
322 <p class=
"p5">MySaw
<span class=
"s1"> :
</span>UGen
<span class=
"s1"> {
</span></p>
323 <p class=
"p7"><span class=
"Apple-tab-span"> </span>*ar {
<span class=
"s2">arg
</span> freq =
440.0, iphase =
0.0;
</p>
324 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>^
<span class=
"s2">this
</span>.multiNew(
<span class=
"s8">'audio'
</span>, freq, iphase)
</p>
325 <p class=
"p7"><span class=
"Apple-tab-span"> </span>}
</p>
326 <p class=
"p7"><span class=
"Apple-tab-span"> </span>*kr {
<span class=
"s2">arg
</span> freq =
440.0, iphase =
0.0;
</p>
327 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>^
<span class=
"s2">this
</span>.multiNew(
<span class=
"s8">'control'
</span>, freq, iphase)
</p>
328 <p class=
"p7"><span class=
"Apple-tab-span"> </span>}
</p>
330 <p class=
"p2"><br></p>
331 <p class=
"p3">____________________________________________________________________
</p>
332 <p class=
"p3">After a recompilation of the class library (Menu: Lang
> Complie Library), the UGen is
</p>
333 <p class=
"p3">ready to be used.
</p>
334 <p class=
"p8"><br></p>
335 <p class=
"p4">// test it:
</p>
336 <p class=
"p8"><br></p>
337 <p class=
"p7">{
<span class=
"s2">MySaw
</span>.ar(
200,
0,
0.1) }.play
</p>
338 <p class=
"p8"><br></p>
339 <p class=
"p2"><br></p>
340 <p class=
"p3">_________________________________________________________
</p>
341 <p class=
"p3"><b>Workflow
</b></p>
342 <p class=
"p2"><br></p>
343 <p class=
"p3">When changing the C-sourcecode, after each rebuilding the project, there is no need to restart SuperCollider or recompile the library (unless you have changed the class definition)
</p>
344 <p class=
"p6"><br></p>
345 <p class=
"p4">// just reboot the server.
</p>
346 <p class=
"p2"><br></p>
347 <p class=
"p16">s.reboot;
</p>
348 <p class=
"p2"><br></p>
349 <p class=
"p3">Note that if you want to use the internal server (e.g. for scoping), you do need to restart
</p>
350 <p class=
"p3">the SuperCollider application.
</p>
351 <p class=
"p3">_________________________________________________________
</p>
352 <p class=
"p8"><br></p>
353 <p class=
"p3"><b>Useful macros
</b></p>
354 <p class=
"p2"><br></p>
355 <p class=
"p3">These are defined in SC_Unit.h.
</p>
356 <p class=
"p8"><br></p>
357 <p class=
"p4">// These return float* pointers to input and output buffers.
</p>
358 <p class=
"p7">#define
<span class=
"s2">IN
</span>(index)
<span class=
"Apple-converted-space"> </span>(unit-
>mInBuf[index])
</p>
359 <p class=
"p7">#define
<span class=
"s2">OUT
</span>(index) (unit-
>mOutBuf[index])
</p>
360 <p class=
"p8"><br></p>
361 <p class=
"p6"><br></p>
362 <p class=
"p4">// These return a float value. Used for control rate inputs and outputs.
</p>
363 <p class=
"p7">#define
<span class=
"s2">IN0
</span>(index)
<span class=
"Apple-converted-space"> </span>(
<span class=
"s2">IN
</span>(index)[
0])
</p>
364 <p class=
"p7">#define
<span class=
"s2">OUT0
</span>(index) (
<span class=
"s2">OUT
</span>(index)[
0])
</p>
365 <p class=
"p8"><br></p>
366 <p class=
"p6"><br></p>
367 <p class=
"p4">// get the rate of the input.
</p>
368 <p class=
"p7">#define
<span class=
"s2">INRATE
</span>(index) (unit-
>mInput[index]-
>mCalcRate)
</p>
369 <p class=
"p8"><br></p>
370 <p class=
"p3">The possible rates are:
</p>
371 <p class=
"p2"><br></p>
372 <p class=
"p7"><span class=
"Apple-tab-span"> </span>calc_ScalarRate
</p>
373 <p class=
"p7"><span class=
"Apple-tab-span"> </span>calc_BufRate
<span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>"control rate"</p>
374 <p class=
"p7"><span class=
"Apple-tab-span"> </span>calc_FullRate
<span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>"audio rate"</p>
375 <p class=
"p8"><br></p>
376 <p class=
"p8"><br></p>
377 <p class=
"p4">// set the calculation function
</p>
378 <p class=
"p7">#define
<span class=
"s2">SETCALC
</span>(func) (unit-
>mCalcFunc = (
<span class=
"s2">UnitCalcFunc
</span>)
&func)
</p>
379 <p class=
"p8"><br></p>
380 <p class=
"p3">SETCALC must be called in the constructor. It may also be called from a calculation function to change to a different calculation function.
</p>
381 <p class=
"p8"><br></p>
382 <p class=
"p6"><br></p>
383 <p class=
"p4">// calculate a slope for control rate interpolation to audio rate.
</p>
384 <p class=
"p7">#define
<span class=
"s2">CALCSLOPE
</span>(next,prev) ((next - prev) * unit-
>mRate-
>mSlopeFactor)
</p>
385 <p class=
"p8"><br></p>
386 <p class=
"p3">CALCSLOPE returns (next - prev) / blocksize which is useful for calculating slopes for linear interpolation.
</p>
387 <p class=
"p8"><br></p>
388 <p class=
"p8"><br></p>
389 <p class=
"p7">#define
<span class=
"s2">SAMPLERATE
</span> (unit-
>mRate-
>mSampleRate)
</p>
390 <p class=
"p8"><br></p>
391 <p class=
"p3">SAMPLERATE returns the sample rate for the unit generator. If it is audio rate then it will be the audio sample rate. If the ugen is control rate, then it will be the control rate. For example, if the ugen is control rate and the auio sample rate is
44100 and the block size is
64, then this will return
44100/
64 or
689.0625.
</p>
392 <p class=
"p8"><br></p>
393 <p class=
"p8"><br></p>
394 <p class=
"p7">#define
<span class=
"s2">SAMPLEDUR
</span> (unit-
>mRate-
>mSampleDur)
</p>
395 <p class=
"p8"><br></p>
396 <p class=
"p3">SAMPLEDUR is simply the reciprocal of the sample rate. It is the seconds per sample.
</p>
397 <p class=
"p8"><br></p>
398 <p class=
"p8"><br></p>
399 <p class=
"p7">#define
<span class=
"s2">BUFLENGTH
</span> (unit-
>mBufLength)
</p>
400 <p class=
"p8"><br></p>
401 <p class=
"p3">BUFLENGTH is equal to the block size if the unit is audio rate and is equal to
1 if the unit is control rate.
</p>
402 <p class=
"p8"><br></p>
403 <p class=
"p8"><br></p>
404 <p class=
"p7">#define
<span class=
"s2">BUFRATE
</span> (unit-
>mRate-
>mBufRate)
</p>
405 <p class=
"p8"><br></p>
406 <p class=
"p3">BUFRATE always returns the control rate.
</p>
407 <p class=
"p2"><br></p>
408 <p class=
"p8"><br></p>
409 <p class=
"p7">#define
<span class=
"s2">BUFDUR
</span> (unit-
>mRate-
>mBufDuration)
</p>
410 <p class=
"p8"><br></p>
411 <p class=
"p3">BUFDUR is the reciprocal of the control rate.
</p>
412 <p class=
"p8"><br></p>
413 <p class=
"p3">____________________________________________________________________
</p>
414 <p class=
"p2"><br></p>
415 <p class=
"p3"><b>Pointer aliasing
</b></p>
416 <p class=
"p8"><br></p>
417 <p class=
"p3">The server uses a
"buffer coloring" algorithm to minimize use of buffers to optimize cache performance. This means that any of the output buffers may be the same as one of the input buffers. This allows for in-place operation which is very efficient. You must be careful however not to write any output sample before you have read all of the input samples. If you did, then the input will be overwritten with output.
</p>
418 <p class=
"p8"><br></p>
419 <p class=
"p4">// This code is correct. It reads the freq input before writing to out.
</p>
420 <p class=
"p7"><span class=
"Apple-tab-span"> </span>for (int i=
0; i
< inNumSamples; ++i)
</p>
421 <p class=
"p7"><span class=
"Apple-tab-span"> </span>{
</p>
422 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>float z = phase;
<span class=
"s10">// store phase in z
</span></p>
423 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>phase += freq[i] * freqmul;
<span class=
"s10">// read freq
</span></p>
424 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>out[i] = z;
</span>// write the output
</p>
425 <p class=
"p8"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></p>
426 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// these if statements wrap the phase a +
1 or -
1.
</p>
427 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>if (phase
>=
1.f) phase -=
2.f;
</p>
428 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>else if (phase
<= -
1.f) phase +=
2.f;
</p>
429 <p class=
"p7"><span class=
"Apple-tab-span"> </span>}
</p>
430 <p class=
"p8"><br></p>
431 <p class=
"p8"><br></p>
432 <p class=
"p4">// If out and freq are the same, then the code below will fail.
</p>
433 <p class=
"p7"><span class=
"Apple-tab-span"> </span>for (int i=
0; i
< inNumSamples; ++i)
</p>
434 <p class=
"p7"><span class=
"Apple-tab-span"> </span>{
</p>
435 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// write the output
</p>
436 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>out[i] = phase;
<span class=
"Apple-converted-space"> </span></p>
437 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>phase += freq[i] * freqmul;
</p>
438 <p class=
"p8"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></p>
439 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// these if statements wrap the phase a +
1 or -
1.
</p>
440 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>if (phase
>=
1.f) phase -=
2.f;
</p>
441 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>else if (phase
<= -
1.f) phase +=
2.f;
</p>
442 <p class=
"p7"><span class=
"Apple-tab-span"> </span>}
</p>
443 <p class=
"p8"><br></p>
444 <p class=
"p3">If your unit generator cannot be written efficiently when pointers are aliased, then you can tell the server this by using one of the following macros when definining it.
</p>
445 <p class=
"p2"><br></p>
446 <p class=
"p7"><span class=
"Apple-tab-span"> </span>DefineSimpleCantAliasUnit(MyUGen);
</p>
447 <p class=
"p8"><span class=
"Apple-tab-span"> </span></p>
448 <p class=
"p7"><span class=
"Apple-tab-span"> </span>DefineDtorCantAliasUnit(MyUGen);
</p>
449 <p class=
"p2"><br></p>
450 <p class=
"p3">The server will then ensure that no output buffers are the same as any input buffers.
</p>
451 <p class=
"p3">____________________________________________________________________
</p>
452 <p class=
"p2"><br></p>
453 <p class=
"p1">A Unit Generator that needs a Dtor
</p>
454 <p class=
"p17"><br></p>
455 <p class=
"p3">This is code for a simple fixed delay line.
</p>
456 <p class=
"p2"><br></p>
457 <p class=
"p2"><br></p>
458 <p class=
"p15"><span class=
"s1">#include
</span>"SC_PlugIn.h"</p>
459 <p class=
"p8"><br></p>
460 <p class=
"p4">// InterfaceTable contains pointers to functions in the host (server).
</p>
461 <p class=
"p5"><span class=
"s1">static
</span>InterfaceTable
<span class=
"s1"> *ft;
</span></p>
462 <p class=
"p8"><br></p>
463 <p class=
"p4">// declare struct to hold unit generator state
</p>
464 <p class=
"p7">struct
<span class=
"s2">MyDelay
</span> : public
<span class=
"s2">Unit
</span></p>
466 <p class=
"p7"><span class=
"Apple-tab-span"> </span>uint32 mDelayLength;
</p>
467 <p class=
"p7"><span class=
"Apple-tab-span"> </span>uint32 mPosition;
</p>
468 <p class=
"p7"><span class=
"Apple-tab-span"> </span>float *mData;
<span class=
"s10">// delay buffer
</span></p>
470 <p class=
"p8"><br></p>
471 <p class=
"p4">// declare unit generator functions
<span class=
"Apple-converted-space"> </span></p>
472 <p class=
"p7">extern
<span class=
"s7">"C"</span></p>
474 <p class=
"p7"><span class=
"Apple-tab-span"> </span>void load(
<span class=
"s2">InterfaceTable
</span> *inTable);
</p>
475 <p class=
"p7"><span class=
"Apple-tab-span"> </span>void
<span class=
"s2">MyDelay_next_notfull
</span>(
<span class=
"s2">MyDelay
</span> *unit, int inNumSamples);
</p>
476 <p class=
"p7"><span class=
"Apple-tab-span"> </span>void
<span class=
"s2">MyDelay_next_full
</span>(
<span class=
"s2">MyDelay
</span> *unit, int inNumSamples);
</p>
477 <p class=
"p5"><span class=
"s1"><span class=
"Apple-tab-span"> </span>void
</span>MyDelay_Ctor
<span class=
"s1">(
</span>MyDelay
<span class=
"s1">* unit);
</span></p>
478 <p class=
"p5"><span class=
"s1"><span class=
"Apple-tab-span"> </span>void
</span>MyDelay_Dtor
<span class=
"s1">(
</span>MyDelay
<span class=
"s1">* unit);
</span></p>
480 <p class=
"p8"><br></p>
481 <p class=
"p4">//////////////////////////////////////////////////////////////////
</p>
482 <p class=
"p8"><br></p>
483 <p class=
"p4">// Ctor is called to initialize the unit generator.
<span class=
"Apple-converted-space"> </span></p>
484 <p class=
"p4">// It only executes once.
</p>
485 <p class=
"p8"><br></p>
486 <p class=
"p4">// A Ctor usually does
3 things.
</p>
487 <p class=
"p4">//
1. set the calculation function.
</p>
488 <p class=
"p4">//
2. initialize the unit generator state variables.
</p>
489 <p class=
"p4">//
3. calculate one sample of output.
</p>
490 <p class=
"p5"><span class=
"s1">void
</span>MyDelay_Ctor
<span class=
"s1">(
</span>MyDelay
<span class=
"s1">* unit)
</span></p>
492 <p class=
"p8"><br></p>
493 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>//
1. set the calculation function.
</p>
494 <p class=
"p5"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>SETCALC
<span class=
"s1">(
</span>MyDelay_next_notfull
<span class=
"s1">);
</span></p>
495 <p class=
"p8"><br></p>
496 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>//
2. initialize the unit generator state variables.
</p>
497 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// get the delay length
</p>
498 <p class=
"p7"><span class=
"Apple-tab-span"> </span>unit-
>mDelayLength = (uint32)(
<span class=
"s2">IN0
</span>(
1) *
<span class=
"s2">SAMPLERATE
</span>);
</p>
499 <p class=
"p8"><span class=
"Apple-tab-span"> </span></p>
500 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// allocate the buffer
</p>
501 <p class=
"p7"><span class=
"Apple-tab-span"> </span>unit-
>mData = (float*)
<span class=
"s2">RTAlloc
</span>(unit-
>mWorld, unit-
>mDelayLength * sizeof(float));
</p>
502 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// RTAlloc allocates out of the real time memory pool of the server
<span class=
"Apple-converted-space"> </span></p>
503 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// which is finite. Note that this memory is not zeroed, so it may contain
</p>
504 <p class=
"p4"><span class=
"Apple-tab-span"> </span>// garbage. Make sure to write before read.
</p>
505 <p class=
"p4"><span class=
"Apple-tab-span"> </span>// The size of the real time memory pool is set using the
</p>
506 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// -m command line argument of the server, or by ways of server.options.memSize
</p>
507 <p class=
"p8"><span class=
"Apple-tab-span"> </span></p>
508 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// initialize the position
</p>
509 <p class=
"p7"><span class=
"Apple-tab-span"> </span>unit-
>mPosition =
0;
</p>
510 <p class=
"p8"><span class=
"Apple-tab-span"> </span></p>
511 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>//
3. calculate one sample of output.
</p>
512 <p class=
"p5"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>MyDelay_next_notfull
<span class=
"s1">(unit,
1);
</span></p>
514 <p class=
"p8"><br></p>
515 <p class=
"p4">//////////////////////////////////////////////////////////////////
</p>
516 <p class=
"p8"><br></p>
517 <p class=
"p4">// Dtor is called to perform any clean up for the unit generator.
<span class=
"Apple-converted-space"> </span></p>
518 <p class=
"p8"><br></p>
519 <p class=
"p5"><span class=
"s1">void
</span>MyDelay_Dtor
<span class=
"s1">(
</span>MyDelay
<span class=
"s1">* unit)
</span></p>
521 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// free the buffer
</p>
522 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"s2">RTFree
</span>(unit-
>mWorld, unit-
>mData);
</p>
524 <p class=
"p8"><br></p>
525 <p class=
"p8"><br></p>
526 <p class=
"p4">//////////////////////////////////////////////////////////////////
</p>
527 <p class=
"p8"><br></p>
528 <p class=
"p4">// The calculation function executes once per control period
<span class=
"Apple-converted-space"> </span></p>
529 <p class=
"p4">// which is typically
64 samples.
</p>
530 <p class=
"p8"><br></p>
531 <p class=
"p4">// calculation function when the buffer has not yet been filled
</p>
532 <p class=
"p7">void
<span class=
"s2">MyDelay_next_notfull
</span>(
<span class=
"s2">MyDelay
</span> *unit, int inNumSamples)
</p>
534 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// get the pointer to the output buffer
</p>
535 <p class=
"p7"><span class=
"Apple-tab-span"> </span>float *out =
<span class=
"s2">OUT
</span>(
0);
</p>
536 <p class=
"p8"><span class=
"Apple-tab-span"> </span></p>
537 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// get the pointer to the input buffer
</p>
538 <p class=
"p7"><span class=
"Apple-tab-span"> </span>float *in =
<span class=
"s2">IN
</span>(
0);
</p>
539 <p class=
"p8"><span class=
"Apple-tab-span"> </span></p>
540 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// get values from struct and store them in local variables.
</p>
541 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// The optimizer will cause them to be loaded it into a register.
</p>
542 <p class=
"p7"><span class=
"Apple-tab-span"> </span>float *data = unit-
>mData;
</p>
543 <p class=
"p7"><span class=
"Apple-tab-span"> </span>uint32 length = unit-
>mDelayLength;
</p>
544 <p class=
"p7"><span class=
"Apple-tab-span"> </span>uint32 position = unit-
>mPosition;
</p>
545 <p class=
"p7"><span class=
"Apple-tab-span"> </span>bool wrapped =
<span class=
"s2">false
</span>;
</p>
546 <p class=
"p8"><span class=
"Apple-tab-span"> </span></p>
547 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// perform a loop for the number of samples in the control period.
</p>
548 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// If this unit is audio rate then inNumSamples will be
64 or whatever
</p>
549 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// the block size is. If this unit is control rate then inNumSamples will
</p>
550 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// be
1.
</p>
551 <p class=
"p7"><span class=
"Apple-tab-span"> </span>for (int i=
0; i
< inNumSamples; ++i)
</p>
552 <p class=
"p7"><span class=
"Apple-tab-span"> </span>{
</p>
553 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// get old value in delay line
</p>
554 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>float z = data[position];
</p>
555 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// store new value in delay line
</p>
556 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>data[position] = in[i];
</p>
557 <p class=
"p8"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></p>
558 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// see if the position went to the end of the buffer
<span class=
"Apple-converted-space"> </span></p>
559 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>if (++position
>= length) {
</p>
560 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>position =
0;
</span>// go back to beginning
</p>
561 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>wrapped =
</span><span class=
"s2">true
</span><span class=
"s1">;
</span>// indicate we have wrapped.
</p>
562 <p class=
"p8"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></p>
563 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// change the calculation function
</p>
564 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// next time, the MyDelay_next_full function will be called
</p>
565 <p class=
"p5"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>SETCALC
<span class=
"s1">(
</span>MyDelay_next_full
<span class=
"s1">);
</span></p>
566 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>}
</p>
567 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// if we have not yet wrapped, then z is garbage from the uninitialized
<span class=
"Apple-converted-space"> </span></p>
568 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// buffer, so output zero. If we have wrapped, then z is a good value.
</p>
569 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>out[i] = wrapped ? z :
0.f;
</p>
570 <p class=
"p7"><span class=
"Apple-tab-span"> </span>}
</p>
571 <p class=
"p8"><br></p>
572 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// store the position back to the struct
</p>
573 <p class=
"p7"><span class=
"Apple-tab-span"> </span>unit-
>mPosition = position;
</p>
575 <p class=
"p8"><br></p>
576 <p class=
"p4">//////////////////////////////////////////////////////////////////
</p>
577 <p class=
"p8"><br></p>
578 <p class=
"p4">// calculation function when the buffer has been filled
</p>
579 <p class=
"p7">void
<span class=
"s2">MyDelay_next_full
</span>(
<span class=
"s2">MyDelay
</span> *unit, int inNumSamples)
</p>
581 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// get the pointer to the output buffer
</p>
582 <p class=
"p7"><span class=
"Apple-tab-span"> </span>float *out =
<span class=
"s2">OUT
</span>(
0);
</p>
583 <p class=
"p8"><span class=
"Apple-tab-span"> </span></p>
584 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// get the pointer to the input buffer
</p>
585 <p class=
"p7"><span class=
"Apple-tab-span"> </span>float *in =
<span class=
"s2">IN
</span>(
0);
</p>
586 <p class=
"p8"><span class=
"Apple-tab-span"> </span></p>
587 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// get values from struct and store them in local variables.
</p>
588 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// The optimizer will cause them to be loaded it into a register.
</p>
589 <p class=
"p7"><span class=
"Apple-tab-span"> </span>float *data = unit-
>mData;
</p>
590 <p class=
"p7"><span class=
"Apple-tab-span"> </span>uint32 length = unit-
>mDelayLength;
</p>
591 <p class=
"p7"><span class=
"Apple-tab-span"> </span>uint32 position = unit-
>mPosition;
</p>
592 <p class=
"p8"><span class=
"Apple-tab-span"> </span></p>
593 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// perform a loop for the number of samples in the control period.
</p>
594 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// If this unit is audio rate then inNumSamples will be
64 or whatever
</p>
595 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// the block size is. If this unit is control rate then inNumSamples will
</p>
596 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// be
1.
</p>
597 <p class=
"p7"><span class=
"Apple-tab-span"> </span>for (int i=
0; i
< inNumSamples; ++i)
</p>
598 <p class=
"p7"><span class=
"Apple-tab-span"> </span>{
</p>
599 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// get old value in delay line
</p>
600 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>float z = data[position];
</p>
601 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// store new value in delay line
</p>
602 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>data[position] = in[i];
</p>
603 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>// see if the position went to the end of the buffer
<span class=
"Apple-converted-space"> </span></p>
604 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>if (++position
>= length) {
</p>
605 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>position =
0;
</span>// go back to beginning
</p>
606 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>}
</p>
607 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>out[i] = z;
</p>
608 <p class=
"p7"><span class=
"Apple-tab-span"> </span>}
</p>
609 <p class=
"p8"><br></p>
610 <p class=
"p4"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>// store the position back to the struct
</p>
611 <p class=
"p7"><span class=
"Apple-tab-span"> </span>unit-
>mPosition = position;
</p>
613 <p class=
"p8"><br></p>
614 <p class=
"p4">////////////////////////////////////////////////////////////////////
</p>
615 <p class=
"p8"><br></p>
616 <p class=
"p4">// the load function is called by the host when the plug-in is loaded
</p>
617 <p class=
"p7">void load(
<span class=
"s2">InterfaceTable
</span> *inTable)
</p>
619 <p class=
"p7"><span class=
"Apple-tab-span"> </span>ft = inTable;
</p>
620 <p class=
"p8"><br></p>
621 <p class=
"p5"><span class=
"s1"><span class=
"Apple-tab-span"> </span></span>DefineDtorUnit
<span class=
"s1">(
</span>MyDelay
<span class=
"s1">);
</span></p>
623 <p class=
"p8"><br></p>
624 <p class=
"p4">////////////////////////////////////////////////////////////////////
</p>
625 <p class=
"p3">____________________________________________________________________
</p>
626 <p class=
"p2"><br></p>
627 <p class=
"p8"><br></p>
628 <p class=
"p4">// In the MyUGens.sc file:
</p>
629 <p class=
"p8"><br></p>
630 <p class=
"p5">MyDelay
<span class=
"s1"> :
</span>UGen
<span class=
"s1"> {
</span></p>
631 <p class=
"p7"><span class=
"Apple-tab-span"> </span>*ar {
<span class=
"s2">arg
</span> in, delaytime=
0.4;
</p>
632 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>^
<span class=
"s2">this
</span>.multiNew(
<span class=
"s8">'audio'
</span>, in, delaytime)
</p>
633 <p class=
"p7"><span class=
"Apple-tab-span"> </span>}
</p>
634 <p class=
"p7"><span class=
"Apple-tab-span"> </span>*kr {
<span class=
"s2">arg
</span> in, delaytime=
0.4;
</p>
635 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>^
<span class=
"s2">this
</span>.multiNew(
<span class=
"s8">'control'
</span>, in, delaytime)
</p>
636 <p class=
"p7"><span class=
"Apple-tab-span"> </span>}
</p>
638 <p class=
"p3">____________________________________________________________________
</p>
639 <p class=
"p8"><br></p>
640 <p class=
"p4">// test it
</p>
643 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"s2">var
</span> z;
</p>
644 <p class=
"p7"><span class=
"Apple-tab-span"> </span>z =
<span class=
"s2">SinOsc
</span>.ar *
<span class=
"s2">Decay
</span>.kr(
<span class=
"s2">Impulse
</span>.kr(
1,
0,
0.2),
0.1);
</p>
645 <p class=
"p7"><span class=
"Apple-tab-span"> </span>[z,
<span class=
"s2">MyDelay
</span>.ar(z,
0.3)]
</p>
646 <p class=
"p7">}.play;
</p>
648 <p class=
"p3">____________________________________________________________________
</p>
649 <p class=
"p2"><br></p>
650 <p class=
"p2"><br></p>
651 <p class=
"p2"><br></p>
652 <p class=
"p3">TO DO:
</p>
653 <p class=
"p3">UGens which access buffers.
</p>
654 <p class=
"p3">UGens which use the built in random number generators.
</p>
655 <p class=
"p2"><br></p>
656 <p class=
"p2"><br></p>